package com.ifonly.common.typeconverter.impl;

import com.ifonly.common.typeconverter.Converter;
import com.ifonly.common.typeconverter.TypeConvert;
import com.ifonly.utils.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author <a href="mailto:ifonlymaster@163.com">ifonly</a>
 * @version 1.0 2015-12-17 21:20
 * @since JDK 1.6
 */
public class ShortArrayConverter implements Converter<short[]> {

    @Override
    public short[] convert(Object value) {
        if (value == null) {
            return null;
        }

        Class valueClass = value.getClass();

        if (!valueClass.isArray()) {
            // source is not an array
            return convertValueToArray(value);
        }

        // source is an array
        return convertArrayToArray(value);
    }

    protected short convertType(Object value) {
        return TypeConvert.toShort(value);
    }

    protected short[] convertToSingleElementArray(Object value) {
        return new short[] {convertType(value)};
    }

    protected short[] convertValueToArray(Object value) {
        if (value instanceof List) {
            List list = (List) value;
            short[] target = new short[list.size()];

            for (int i = 0; i < list.size(); i++) {
                Object element = list.get(i);
                target[i] = convertType(element);
            }

            return target;
        }

        if (value instanceof Collection) {
            Collection collection = (Collection) value;
            short[] target = new short[collection.size()];

            int i = 0;
            for (Object element : collection) {
                target[i] = convertType(element);
                i++;
            }

            return target;
        }

        if (value instanceof Iterable) {
            Iterable iterable = (Iterable) value;

            ArrayList<Short> shortArrayList = new ArrayList<Short>();

            for (Object element : iterable) {
                short convertedValue = convertType(element);
                shortArrayList.add(Short.valueOf(convertedValue));
            }

            short[] array = new short[shortArrayList.size()];

            for (int i = 0; i < shortArrayList.size(); i++) {
                Short s = shortArrayList.get(i);
                array[i] = s;
            }

            return array;
        }

        if (value instanceof CharSequence) {
            String[] strings = StringUtils.splitc(value.toString(), Converter.NUMBER_DELIMITERS);
            return convertArrayToArray(strings);
        }

        // everything else:
        return convertToSingleElementArray(value);
    }

    protected short[] convertArrayToArray(Object value) {
        Class valueComponentType = value.getClass().getComponentType();

        if (valueComponentType == Short.class) {
            // equal types, no conversion needed
            return (short[]) value;
        }

        short[] result;

        if (valueComponentType.isPrimitive()) {
            // convert primitive array to target array
            result = convertPrimitiveArrayToArray(value, valueComponentType);
        } else {
            // convert object array to target array
            Object[] array = (Object[]) value;
            result = convertObjectArrayToArray(array, valueComponentType);


        }

        return result;
    }

    private short[] convertObjectArrayToArray(Object[] array, Class valueComponentType) {
        short[] result = new short[array.length];

        for (int i = 0; i < array.length; i++) {
            result[i] = convertType(array[i]);
        }
        return result;
    }

    protected short[] convertPrimitiveArrayToArray(Object value, Class primitiveComponentType) {
        short[] result = null;

        if (primitiveComponentType == Short[].class) {
            return (short[]) value;
        }

        if (primitiveComponentType == int.class) {
            int[] array = (int[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == long.class) {
            long[] array = (long[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == float.class) {
            float[] array = (float[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == double.class) {
            double[] array = (double[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == byte.class) {
            byte[] array = (byte[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == char.class) {
            char[] array = (char[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) array[i];
            }
        } else if (primitiveComponentType == boolean.class) {
            boolean[] array = (boolean[]) value;
            result = new short[array.length];
            for (int i = 0; i < array.length; i++) {
                result[i] = (short) (array[i] ? 1 : 0);
            }
        }
        return result;
    }

}
